package com.sadhoc.router.pdu;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;

public class HDPacket implements Serializable {
	
	private static final long serialVersionUID = 2446523778533906590L;
	private byte[] destinationIP	= null;
	private byte[] sourceIP 		= null;
	private byte transport			= 0;
	private byte type				= 0;
	private byte[] data				= null;
	
	/*
	 * Constructor - intended for sending HDPackets
	 */
	public HDPacket(String destinationIP, String sourceIP, byte transport, byte type, byte[] data) throws UnknownHostException {
		
		this.destinationIP = InetAddress.getByName(destinationIP).getAddress();
		this.sourceIP = InetAddress.getByName(sourceIP).getAddress();
		this.type = type;
		this.data = data;
		this.transport = transport;
		
	}
	
	/*
	 * Constructor - intended for sending HDPackets
	 */
	public HDPacket(String destinationIP, String sourceIP, byte transport, byte type, Object o) throws UnknownHostException {
		
		this.destinationIP = InetAddress.getByName(destinationIP).getAddress();
		this.sourceIP = InetAddress.getByName(sourceIP).getAddress();
		this.type = type;
		
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		try {
			ObjectOutputStream oos = new ObjectOutputStream(bos); 
			oos.writeObject(o);
			oos.flush(); 
			oos.close(); 
			bos.close();
			this.data = bos.toByteArray ();
		}
		catch (IOException ex) {
			ex.printStackTrace();
		}

		this.transport = transport;
		
	}
	
	/*
	 * Constructor - intended when UDP datagram is received
	 */
	public HDPacket(byte[] rawPacket) throws UnknownHostException {
		
		destinationIP = new byte[4];
		sourceIP = new byte[4];
		data = new byte[rawPacket.length - 10];
		
		System.arraycopy(rawPacket, 0, destinationIP, 0, 4);
		System.arraycopy(rawPacket, 4, sourceIP, 0, 4);
		transport = rawPacket[8];
		type = rawPacket[9];
		
		System.arraycopy(rawPacket, 10, data, 0, rawPacket.length - 10);
		
		// Lazy way to verify the packet - will throw an exception if it's not valid
		InetAddress.getByAddress(destinationIP);
		InetAddress.getByAddress(sourceIP);
		
	}
	
	/*
	 * Returns the HDPacket as byte array defined above
	 */
	public byte[] getBytes() {
		
		byte[] ret = new byte[10 + data.length];
		
		System.arraycopy(destinationIP, 0, ret, 0, 4);
		System.arraycopy(sourceIP, 0, ret, 4, 4);
		ret[8] = transport;
		ret[9] = type;
		System.arraycopy(data, 0, ret, 10, data.length);
		
		return ret;
		
	}
	
	/*
	 * Returns the destination IP as a string
	 */
	public String getDestinationIP() {
		
		try {
			return (InetAddress.getByAddress(destinationIP).getHostAddress());
		} catch (UnknownHostException e) {
			return null;
		}
		
	}
	
	/*
	 * Returns the source IP as a string
	 */
	public String getSourceIP() {
		
		try {
			return (InetAddress.getByAddress(sourceIP).getHostAddress());
		} catch (UnknownHostException e) {
			return null;
		}
		
	}
	
	/*
	 * Returns the transport type
	 */
	public byte getTransport() {
		
		return transport;
		
	}
	
	/*
	 * Returns the HDPacket type field
	 */
	public byte getType() {
		
		return type;
		
	}
		
	/*
	 * Returns the payload as a byte array
	 */
	public byte[] getData() {
		
		return data;
		
	}
	
	/*
	 * Returns the payload as an object
	 */
	public Object getDataAsObject() {
		
		Object obj = null;
		try {
			ByteArrayInputStream bis = new ByteArrayInputStream (this.data);
			ObjectInputStream ois = new ObjectInputStream (bis);
			obj = ois.readObject();
		}
		catch (IOException ex) {
			ex.printStackTrace();
		}
		catch (ClassNotFoundException ex) {
			ex.printStackTrace();
		}
		return obj;
		
	}

}
